๐Ÿ”ข Numeri Negativi e Reali in Binario

Rappresentazione con segno, virgola fissa e virgola mobile IEEE 754

๐Ÿ“š 1. Introduzione

Finora abbiamo visto come rappresentare numeri interi positivi in binario. Ma come facciamo a rappresentare numeri negativi e numeri con la virgola? Questo รจ fondamentale per permettere ai computer di eseguire calcoli realistici.

๐Ÿ’ก Problemi da risolvere
  • Numeri negativi: Come distinguere -5 da +5 in binario?
  • Numeri decimali: Come rappresentare 3.14, 0.5, -2.75?
  • Range e precisione: Come bilanciare numeri molto grandi e molto piccoli?

๐Ÿ“Š Metodi di rappresentazione

Metodo Cosa rappresenta Complessitร  Uso
Segno e Modulo Numeri interi con segno โญ Facile Didattico (poco usato)
Complemento a 2 Numeri interi con segno โญโญ Media Standard per interi
Virgola Fissa Numeri decimali con precisione fissa โญโญ Media DSP, finanza
Virgola Mobile (IEEE 754) Numeri decimali con range ampio โญโญโญ Avanzata Standard universale

โž– 2. Rappresentazione dei Numeri Negativi

๐Ÿ“‹ Metodo 1: Segno e Modulo (Sign-Magnitude)

Il metodo piรน intuitivo: usiamo 1 bit per il segno (0=positivo, 1=negativo) e i restanti bit per il valore assoluto.

Esempio con 8 bit:

S 7 6 5 4 3 2 1

S = bit di segno (0=+, 1=-) | 7-1 = valore assoluto

Esempi con 8 bit: +5 = 0 0000101 -5 = 1 0000101 +42 = 0 0101010 -42 = 1 0101010 +0 = 0 0000000 -0 = 1 0000000 โ† Problema: due rappresentazioni per zero!
โš ๏ธ Problemi del segno-modulo
  • Esistono due zeri (+0 e -0)
  • Hardware complesso per addizioni/sottrazioni
  • Range asimmetrico: con 8 bit vai da -127 a +127

๐Ÿ“‹ Metodo 2: Complemento a 1 (One's Complement)

Per ottenere il negativo di un numero, si invertono tutti i bit.

Esempi con 8 bit: +5 = 00000101 -5 = 11111010 (tutti i bit invertiti) +42 = 00101010 -42 = 11010101 +0 = 00000000 -0 = 11111111 โ† Ancora due zeri!
โš ๏ธ Problema del complemento a 1

Persiste il problema dei due zeri e richiede correzioni nell'hardware.

๐Ÿ“‹ Metodo 3: Complemento a 2 (Two's Complement) โœ…

Questo รจ il metodo standard usato in tutti i computer moderni! Per ottenere il negativo: inverti tutti i bit e aggiungi 1.

โœ… Vantaggi del complemento a 2
  • Un solo zero (00000000)
  • Addizione e sottrazione usano lo stesso circuito
  • Range: da -2โฟโปยน a +2โฟโปยน-1
  • Estensione del segno semplice

Calcolare -42 in complemento a 2 (8 bit)

Passo 1: Scrivi +42 in binario 00101010 Passo 2: Inverti tutti i bit (complemento a 1) 11010101 Passo 3: Aggiungi 1 11010101 + 1 ---------- 11010110 โ† Questo รจ -42 in complemento a 2!

๐Ÿ“Š Range con complemento a 2

Bit Range Piรน piccolo (binario) Piรน grande (binario)
4 bit -8 a +7 1000 = -8 0111 = +7
8 bit -128 a +127 10000000 = -128 01111111 = +127
16 bit -32768 a +32767 1000000000000000 0111111111111111
32 bit -2ยณยน a +2ยณยน-1 โ‰ˆ -2.1 miliardi โ‰ˆ +2.1 miliardi
๐Ÿ’ก Come riconoscere il segno

In complemento a 2, guarda il bit piรน significativo (MSB):

  • MSB = 0 โ†’ Numero positivo o zero
  • MSB = 1 โ†’ Numero negativo

๐Ÿ“ 3. Virgola Fissa (Fixed-Point)

Nella rappresentazione a virgola fissa, si stabilisce una volta per tutte quanti bit dedicare alla parte intera e quanti alla parte frazionaria.

๐Ÿ“Š Formato Qm.n

La notazione Qm.n indica:

  • m = bit per la parte intera (incluso segno)
  • n = bit per la parte frazionaria

Esempio: Q4.4 (8 bit totali)

S 2 1 0 . -1 -2 -3 -4

Parte intera (4 bit) | Virgola fissa | Parte frazionaria (4 bit)

Esempio: Rappresentare 5.75 in Q4.4

Passo 1: Converti la parte intera 5โ‚โ‚€ = 0101โ‚‚ Passo 2: Converti la parte frazionaria 0.75 = 0.5 + 0.25 = 1/2 + 1/4 = 2โปยน + 2โปยฒ = 0.1100โ‚‚ Passo 3: Combina 5.75 = 0101.1100 In Q4.4: 01011100

๐ŸŽฏ Conversione parte frazionaria

Come convertire 0.625 in binario

Moltiplica per 2 ripetutamente: 0.625 ร— 2 = 1.25 โ†’ Bit: 1, resto 0.25 0.25 ร— 2 = 0.5 โ†’ Bit: 0, resto 0.5 0.5 ร— 2 = 1.0 โ†’ Bit: 1, resto 0 Risultato: 0.625โ‚โ‚€ = 0.101โ‚‚
โš ๏ธ Limiti della virgola fissa
  • Range limitato: Q4.4 va da -8.0 a +7.9375
  • Precisione fissa: Con 4 bit frazionari, step minimo = 2โปโด = 0.0625
  • Sprechi: Se rappresenti 0.001, sprechi i bit della parte intera

๐Ÿ“Š Esempi di formati a virgola fissa

Formato Bit totali Parte intera Parte frazionaria Range Precisione
Q4.4 8 4 4 -8 a +7.9375 0.0625
Q8.8 16 8 8 -128 a +127.996 0.00390625
Q16.16 32 16 16 -32768 a +32767.999 0.0000152587

๐ŸŒŠ 4. Virgola Mobile (Floating-Point)

La rappresentazione a virgola mobile (floating-point) risolve i limiti della virgola fissa permettendo di rappresentare numeri con range enorme e precisione variabile.

๐Ÿ’ก Notazione Scientifica

La virgola mobile si basa sulla notazione scientifica:

๐Ÿ’ก Formato generale
Numero = (-1)หข ร— M ร— B^E Dove: โ€ข s = bit di segno (0 o 1) โ€ข M = mantissa (parte significativa) โ€ข B = base (2 per binario) โ€ข E = esponente

Esempi in decimale:

  • 123.45 = 1.2345 ร— 10ยฒ
  • 0.00056 = 5.6 ร— 10โปโด
  • -6789000 = -6.789 ร— 10โถ

๐Ÿ“Š Vantaggi della virgola mobile

โœ… Perchรฉ usare la virgola mobile?
  • Range enorme: Da โ‰ˆ10โปยณโธ a โ‰ˆ10ยณโธ con 32 bit
  • Precisione relativa: Piรน cifre significative per numeri piccoli e grandi
  • Standard universale: IEEE 754 usato in tutti i processori
  • Hardware efficiente: FPU (Floating-Point Unit) dedicate

๐Ÿ”ข 5. IEEE 754 Single Precision (32 bit)

Lo standard IEEE 754 single precision (chiamato anche float in molti linguaggi) usa 32 bit divisi in tre parti.

Struttura di un float (32 bit):

S E E E E E E E E M M M ... M M M

โ–  Segno (1 bit) | โ–  Esponente (8 bit) | โ–  Mantissa (23 bit)

๐Ÿ“‹ Componenti del formato

๐Ÿ”ด Bit di Segno (1 bit)
  • 0 = numero positivo
  • 1 = numero negativo
๐ŸŸก Esponente (8 bit) - Bias 127

L'esponente รจ rappresentato con bias +127:

  • Esponente memorizzato = Esponente reale + 127
  • Range: da -126 a +127
  • 00000000 e 11111111 sono riservati per casi speciali
Esempi: Esponente reale = 0 โ†’ Memorizzato: 127 (01111111) Esponente reale = 5 โ†’ Memorizzato: 132 (10000100) Esponente reale = -3 โ†’ Memorizzato: 124 (01111100)
๐Ÿ”ต Mantissa (23 bit) - Normalizzata

La mantissa rappresenta la parte frazionaria con un 1 implicito:

  • Formato: 1.xxxxxxxxxxxxxxxxx (1 + 23 bit frazionari)
  • Il "1." รจ implicito e non viene memorizzato (bit nascosto)
  • Si guadagna 1 bit di precisione!

๐ŸŽฏ Formula completa

โœ… Formula IEEE 754 Single Precision
Valore = (-1)หข ร— (1 + mantissa) ร— 2^(esponente - 127) Dove: โ€ข s = bit di segno โ€ข mantissa = 23 bit interpretati come frazione โ€ข esponente = 8 bit interpretati come intero senza segno

Esempio completo: Rappresentare -12.375 in IEEE 754 single precision

Passo 1: Determina il segno -12.375 รจ negativo โ†’ s = 1 Passo 2: Converti il valore assoluto in binario 12โ‚โ‚€ = 1100โ‚‚ 0.375 = 0.25 + 0.125 = 2โปยฒ + 2โปยณ = 0.011โ‚‚ 12.375 = 1100.011โ‚‚ Passo 3: Normalizza (sposta la virgola dopo il primo 1) 1100.011 = 1.100011 ร— 2ยณ Esponente reale: 3 Passo 4: Calcola l'esponente con bias Esponente memorizzato = 3 + 127 = 130 130โ‚โ‚€ = 10000010โ‚‚ Passo 5: Estrai la mantissa (senza il "1." iniziale) 1.100011 โ†’ mantissa = 10001100000000000000000 (23 bit) Passo 6: Combina tutto S: 1 E: 10000010 M: 10001100000000000000000 Risultato: 1 10000010 10001100000000000000000

๐Ÿ“Š Valori speciali

Valore Esponente Mantissa Significato
Zero 00000000 tutti 0 ยฑ0 (dipende dal segno)
Denormalizzati 00000000 non tutti 0 Numeri molto piccoli
Infinito 11111111 tutti 0 ยฑโˆž (overflow)
NaN 11111111 non tutti 0 Not a Number (0/0, โˆš-1)

๐Ÿ“ Precisione e Range

๐Ÿ’ก Caratteristiche del float (32 bit)
  • Precisione: โ‰ˆ 7 cifre decimali significative
  • Range positivo: da โ‰ˆ1.4 ร— 10โปโดโต a โ‰ˆ3.4 ร— 10ยณโธ
  • Epsilon macchina: โ‰ˆ1.19 ร— 10โปโท (piรน piccola differenza rappresentabile)

๐Ÿ”ข๐Ÿ”ข 6. IEEE 754 Double Precision (64 bit)

Il formato double precision (chiamato double) usa 64 bit per una precisione e range maggiori.

Struttura di un double (64 bit):

S E ร—11 M ร—52

โ–  Segno (1 bit) | โ–  Esponente (11 bit) | โ–  Mantissa (52 bit)

๐Ÿ”ต Differenze rispetto al float
Componente Float (32 bit) Double (64 bit)
Bit esponente 8 bit 11 bit
Bias esponente 127 1023
Bit mantissa 23 bit 52 bit
Precisione decimale โ‰ˆ 7 cifre โ‰ˆ 15-16 cifre
Range โ‰ˆยฑ10ยณโธ โ‰ˆยฑ10ยณโฐโธ

๐ŸŽฏ Formula Double Precision

โœ… Formula IEEE 754 Double Precision
Valore = (-1)หข ร— (1 + mantissa) ร— 2^(esponente - 1023) Dove: โ€ข s = bit di segno โ€ข mantissa = 52 bit interpretati come frazione โ€ข esponente = 11 bit interpretati come intero senza segno โ€ข bias = 1023 (invece di 127)

๐ŸŽญ 7. Casi Speciali e Valori Particolari

๐Ÿ”ด Zero

+0: 0 00000000 00000000000000000000000 -0: 1 00000000 00000000000000000000000 Nota: +0 e -0 sono considerati uguali nelle operazioni!

โ™พ๏ธ Infinito

๐Ÿ’ก Quando si ottiene infinito?
  • Divisione per zero: 1.0 / 0.0 = +โˆž
  • Overflow: numero troppo grande
  • Operazioni: โˆž + 5 = โˆž, โˆž ร— 2 = โˆž
+โˆž: 0 11111111 00000000000000000000000 -โˆž: 1 11111111 00000000000000000000000

๐Ÿšซ NaN (Not a Number)

โš ๏ธ Operazioni che producono NaN
  • 0.0 / 0.0
  • โˆž - โˆž
  • โˆž / โˆž
  • โˆš(-1)
  • log(-5)
NaN: s 11111111 qualsiasi valore โ‰  0 Proprietร  di NaN: โ€ข NaN โ‰  NaN (anche con se stesso!) โ€ข Qualsiasi operazione con NaN produce NaN โ€ข NaN si propaga attraverso i calcoli

๐Ÿ”ฌ Numeri Denormalizzati (Subnormal)

I numeri denormalizzati permettono di rappresentare valori molto vicini allo zero, riempiendo il "gap" tra 0 e il piรน piccolo numero normalizzato.

๐Ÿ’ก Numeri denormalizzati
  • Esponente = 00000000
  • Mantissa โ‰  00000000...
  • Il "1." implicito diventa "0."
  • Formula: (-1)หข ร— 0.mantissa ร— 2โปยนยฒโถ

๐Ÿ”„ 8. Conversioni Pratiche

๐Ÿ“ฅ Da decimale a IEEE 754

Algoritmo completo

  1. Gestisci il segno: Se negativo, s=1 e lavora col valore assoluto
  2. Converti in binario: Sia parte intera che frazionaria
  3. Normalizza: Sposta la virgola dopo il primo 1 e conta l'esponente
  4. Calcola esponente con bias: E_memorizzato = E_reale + 127 (float)
  5. Estrai mantissa: I bit dopo il punto, senza il "1." iniziale
  6. Combina: [S][Esponente][Mantissa]

๐Ÿ“ค Da IEEE 754 a decimale

Algoritmo completo

  1. Estrai i bit: Separa segno, esponente e mantissa
  2. Verifica casi speciali: Zero, infinito, NaN
  3. Calcola esponente reale: E_reale = E_memorizzato - 127
  4. Ricostruisci mantissa: 1.mantissa in decimale
  5. Applica la formula: (-1)หข ร— mantissa ร— 2^E_reale

Esempio: Decodificare 0 10000010 10001100000000000000000

Passo 1: Estrai i componenti Segno: 0 (positivo) Esponente: 10000010 = 130โ‚โ‚€ Mantissa: 10001100000000000000000 Passo 2: Calcola esponente reale E_reale = 130 - 127 = 3 Passo 3: Ricostruisci la mantissa 1.10001100000000000000000 = 1 + 1ร—2โปยน + 0ร—2โปยฒ + 0ร—2โปยณ + 0ร—2โปโด + 1ร—2โปโต + 1ร—2โปโถ = 1 + 0.5 + 0.03125 + 0.015625 = 1.546875 Passo 4: Applica la formula Valore = (+1) ร— 1.546875 ร— 2ยณ = 1.546875 ร— 8 = 12.375 Risultato: 12.375โ‚โ‚€

๐Ÿงฎ 9. Calcolatori Interattivi

๐Ÿ”ข Convertitore Complemento a 2

Complemento a 2

๐Ÿ“ Convertitore Virgola Fissa

Fixed-Point Converter

๐ŸŒŠ Convertitore IEEE 754

IEEE 754 Floating-Point

๐Ÿ” Decodificatore IEEE 754

Decodifica binario IEEE 754

๐Ÿ“ 10. Esercizi Interattivi

๐ŸŽฒ Generatore di Esercizi

Esercizi Complemento a 2

Esercizi Virgola Fissa

Esercizi IEEE 754

โš ๏ธ 11. Errori Comuni e Insidie

โŒ Errore 1: Confrontare float con ==
// SBAGLIATO if (0.1 + 0.2 == 0.3) { // Puรฒ essere falso! // codice } // CORRETTO const epsilon = 1e-10; if (Math.abs((0.1 + 0.2) - 0.3) < epsilon) { // codice }

Motivo: Gli errori di arrotondamento rendono i confronti diretti inaffidabili.

โŒ Errore 2: Dimenticare il bias dell'esponente

Problema: Usare l'esponente binario direttamente senza sottrarre il bias
Soluzione: Float: E_reale = E_binario - 127, Double: E_reale = E_binario - 1023

โŒ Errore 3: Dimenticare il bit implicito

Problema: Trattare la mantissa come 0.xxx invece di 1.xxx
Soluzione: La mantissa normalizzata รจ sempre 1.xxx (il "1." รจ implicito!)

โŒ Errore 4: Overflow/Underflow non gestito
float x = 3.4e38; float y = x * 10; // Overflow โ†’ +โˆž float z = 1.0e-38; float w = z / 1e10; // Underflow โ†’ 0 (o denormalizzato)

Soluzione: Verifica sempre i risultati di calcoli con numeri estremi.

โŒ Errore 5: Accumulo di errori
// SBAGLIATO (errori si accumulano) float sum = 0.0; for (int i = 0; i < 10000000; i++) { sum += 0.1; } // sum โ‰  1000000.0 esattamente! // MIGLIORE float sum = 0.1 * 10000000; // Meno passaggi = meno errori
โŒ Errore 6: Perdita di precisione nelle sottrazioni
float a = 1.0000001; float b = 1.0; float diff = a - b; // Catastrofica cancellazione! // La precisione relativa si perde quando // si sottraggono numeri molto simili

Soluzione: Riorganizza i calcoli per evitare sottrazioni tra numeri simili.

๐ŸŽฏ 12. Trucchi e Ottimizzazioni

โœ… Trucco 1: Test rapido del segno
// In C/C++, per vedere se un float รจ negativo: int bits = *(int*)&myFloat; bool isNegative = (bits < 0); // MSB = 1 // Funziona perchรฉ il bit di segno รจ il MSB
โœ… Trucco 2: Confronto veloce di float
// Confronta float come interi (funziona per positivi!) int a_bits = *(int*)&float_a; int b_bits = *(int*)&float_b; // Per IEEE 754, l'ordine binario = ordine numerico if (a_bits < b_bits) { // float_a < float_b }
โœ… Trucco 3: Inversione rapida della radice quadrata (Fast Inverse Square Root)
// Famoso trucco del gioco Quake III float InvSqrt(float x) { float xhalf = 0.5f * x; int i = *(int*)&x; i = 0x5f3759df - (i >> 1); // Magia! x = *(float*)&i; x = x * (1.5f - xhalf * x * x); // Newton iteration return x; } // Calcola 1/โˆšx molto piรน velocemente dell'hardware!
โœ… Trucco 4: Verifica se float รจ potenza di 2
bool isPowerOf2(float x) { // Se รจ potenza di 2, la mantissa รจ tutta 0 int bits = *(int*)&x; int mantissa = bits & 0x7FFFFF; return (mantissa == 0 && x > 0); }
โœ… Trucco 5: Estrazione dell'esponente
int getExponent(float x) { int bits = *(int*)&x; int exp = (bits >> 23) & 0xFF; // Estrai 8 bit return exp - 127; // Rimuovi bias } // Utile per calcoli veloci di logโ‚‚(x)

โœ… 13. Checklist di Autovalutazione

๐Ÿ“‹ Numeri Negativi
  • โ˜ Conosco le differenze tra segno-modulo, complemento a 1 e complemento a 2
  • โ˜ So calcolare il complemento a 2 di un numero
  • โ˜ Capisco perchรฉ il complemento a 2 รจ lo standard
  • โ˜ So qual รจ il range di valori per N bit in complemento a 2
  • โ˜ Riconosco un numero negativo guardando il MSB
๐Ÿ“‹ Virgola Fissa
  • โ˜ Capisco il formato Qm.n
  • โ˜ So convertire numeri decimali in virgola fissa
  • โ˜ So convertire la parte frazionaria con moltiplicazioni successive
  • โ˜ Conosco i limiti di range e precisione
๐Ÿ“‹ IEEE 754 Single Precision
  • โ˜ Conosco la struttura: 1 bit segno + 8 bit esponente + 23 bit mantissa
  • โ˜ Capisco il concetto di bias (127 per float)
  • โ˜ So cos'รจ il bit implicito nella mantissa
  • โ˜ So normalizzare un numero binario (1.xxx ร— 2โฟ)
  • โ˜ So convertire da decimale a IEEE 754
  • โ˜ So decodificare un numero IEEE 754 in decimale
  • โ˜ Riconosco i valori speciali (ยฑ0, ยฑโˆž, NaN)
๐Ÿ“‹ IEEE 754 Double Precision
  • โ˜ Conosco le differenze tra float e double
  • โ˜ So che il bias รจ 1023 per double
  • โ˜ Capisco il trade-off tra precisione e range
๐Ÿ“‹ Concetti Avanzati
  • โ˜ Capisco gli errori di arrotondamento
  • โ˜ So perchรฉ non si devono confrontare float con ==
  • โ˜ Conosco il concetto di epsilon macchina
  • โ˜ Comprendo overflow e underflow
  • โ˜ So cosa sono i numeri denormalizzati

๐ŸŽ“ Conclusione

Complimenti! Hai completato questa guida completa sulla rappresentazione di numeri negativi e reali in binario!

Ora comprendi come i computer rappresentano realmente tutti i tipi di numeri, dai negativi ai decimali. Questa conoscenza รจ fondamentale per capire i limiti e le caratteristiche dei calcoli al computer. ๐Ÿ’ป

Continua a esercitarti con i calcolatori interattivi e gli esercizi randomici! ๐ŸŽฏ

"In informatica, 2.0 + 2.0 = 4.0, ma 0.1 + 0.2 potrebbe non essere esattamente 0.3!" ๐Ÿ˜„